import os

import wx
from wx.lib.pubsub import Publisher as pub

from .utils import list_to_lines
from .model import Model
from .view import View

file_path = os.path.split(__file__)[0]
search_dbpath = os.path.join(file_path, "View_data_search_database.sqlite")

class Controller(object):
    "This class handles access to the model from the GUI."
    def __init__(self):
        pass

    def setup(self, search_dbpath=search_dbpath,
                    show_frames=True):

        self.model = Model(search_dbpath)
        self.view  = View()
        self.view.show_frames(show_frames)

    def setup_subscriptions(self):
        pub.subscribe(self._open_a_database, "OPEN A DATABASE")
        pub.subscribe(self._database_opened, "DATABASE OPENED")
        pub.subscribe(self._search_database, "SEARCH DATABASE")
        pub.subscribe(self._export_data, "EXPORT DATA")

        pub.subscribe(self._right_clicked_in_grid, "RIGHT-CLICKED IN GRID")
        pub.subscribe(self._right_clicked_experiment_in_tree, 
                      "RIGHT-CLICKED EXPERIMENT IN TREE")

        pub.subscribe(self._search_panel_adjust, "SEARCH PANEL PREV")
        pub.subscribe(self._search_panel_adjust, "SEARCH PANEL NEXT")

    def _open_a_database(self, message):
        dlg = wx.FileDialog(
            self.view.dp_frame, message="Choose a Database File to Open",
            defaultDir="",
            defaultFile="",
            wildcard="SQLite Database (*.sqlite)|*.sqlite",
            style=wx.OPEN)

        # Show the dialog and retrieve the user response. 
        #     If it is the OK response, process the data.
        if dlg.ShowModal() == wx.ID_OK:
            # This returns a Python list of files that were selected.
            paths = dlg.GetPaths()
            self.model.open_database(paths[0])
        dlg.Destroy()

    def _database_opened(self, message):
        dbid = message.data
        pub.sendMessage("BUILD TREE", self.model.experiment_tree[dbid])
        pub.sendMessage("UPDATE DATABASE CHOOSER", dbid)

    def _search_database(self, message):
        dbid, search_string = message.data
        expe_ids = self.model.search(dbid, search_string)
        experiments = [self.model.experiments[dbid][expe_id] 
                       for expe_id in expe_ids]
        pub.sendMessage("SEARCH GRID SET EXPERIMENTS", experiments)
        pub.sendMessage("SEARCH GRID SET IN CART", self.model.cart.items)
        dlg = wx.MessageDialog(
            self.view.dp_frame, 
            message="Searching '%s'...\n Found %d results." % 
                    (dbid, len(expe_ids)),
            style=wx.OK|wx.CENTRE|wx.ICON_INFORMATION)
        dlg.ShowModal()

    def _search_panel_adjust(self, message):
        if 'NEXT' in message.topic[0]:
            increment = 1
        else:
            increment = -1
        present_string, bud = message.data
        if present_string == bud:
            search_db = self.model.search_db
            self.good_search_strings = search_db.get_search_strings(bud)
            text_ctrl = self.view.data_picker.search_panel.search_text_ctrl
            if self.good_search_strings:
                text_ctrl.ChangeValue(self.good_search_strings[0])
        else:
            index = self.good_search_strings.index(present_string)
            new_index = (index+increment)%len(self.good_search_strings)
            text_ctrl = self.view.data_picker.search_panel.search_text_ctrl
            text_ctrl.ChangeValue(self.good_search_strings[new_index])
        text_ctrl.SetSelection(0,len(bud))

    def _export_data(self, message):
        overwriting_files = []
        num_exps = len(self.model.cart.items)
        if num_exps == 0:
            dlg = wx.MessageDialog(
                self.view.dp_frame, 
                message="There are no experiments in the cart to export.",
                style=wx.OK|wx.CENTRE|wx.ICON_EXCLAMATION)
            dlg.ShowModal()
            return
        dlg = wx.DirDialog(self.view.dp_frame,
                     message="Select a directory to export %d experiments to." %
                     num_exps)

        if dlg.ShowModal() == wx.ID_OK:
            path = dlg.GetPath()
            commands = []
            for exp in self.model.cart.items:
                commands.extend(exp.get_export_commands(path))
            # commands should be of the form [ cp "a" "b" ]
            for command in commands:
                tokens = command.split('"')
                new_file = tokens[3]
                if os.path.exists(new_file):
                    overwriting_files.append(os.path.split(new_file)[-1])
        else:
            return
        dlg.Destroy()
        num_files = len(os.listdir(path))
        if overwriting_files:
            message = "%d files would be overwritten in directory:\n\n" %\
                      len(overwritting_files)
            message += "%s\n" % path
            message += "Including:\n%s\nContinue with export?" %\
                       list_to_lines(overwritting_files, max=10)
            dlg = wx.MessageDialog(
                self.view.dp_frame, 
                message=message,
                style=wx.OK|wx.CANCEL|wx.CENTRE|wx.ICON_EXCLAMATION)
            if dlg.ShowModal() != wx.ID_OK:
                dlg.Destroy()
                self.export_data(message)
                return
            else:
                dlg.Destroy()
        # don't bother trying to reconstruct frames before svn revision 199
        # because things were too immature then.
        # we weren't even saving frame time information then anyways.
        ask_about_save_frames = False
        for exp in self.model.cart.items:
            if exp.stim_svn_revision >= 199:
                ask_about_save_frames = True
        if ask_about_save_frames:
            kwargs = self._display_export_dialog()
        else:
            kwargs= {'save_frames':False}

        num_items = len(self.model.cart.items)
        dlg = wx.ProgressDialog('Export Progress', 
                                'Preparing to export data', 
                                parent=self.view.dp_frame, 
                                maximum=num_items)
        for i, exp in enumerate(self.model.cart.items):
            dlg.Update(i,'Exporting experiment #%d' % exp.expe_id)
            wx.Yield()
            exp.export(path, **kwargs)
        dlg.Destroy()

    def _right_clicked_experiment_in_tree(self, message):
        experiment = message.data
        self.model.cart.add_or_remove(experiment)

    def _right_clicked_in_grid(self, message):
        experiment = message.data
        self.model.cart.add_or_remove(experiment)

    def _display_export_dialog(self):
        dlg = ExportDialog(self.view.dp_frame)
        dlg.ShowModal()
        kwargs = dlg.kwargs
        dlg.Destroy()
        return kwargs


class ExportDialog(wx.Dialog):
    def __init__(self, *args, **kwargs):
        wx.Dialog.__init__(self, *args, **kwargs)
        panel = wx.Panel(self)
        directions = wx.StaticText(panel, wx.ID_ANY, 
                                 'Choose the settings for saving frame images.')

        sff_pre = wx.StaticText(panel, wx.ID_ANY,
                                 'Save Frames Factor: ')
        sff_textctrl = wx.TextCtrl(panel, size=(150,-1))
        sff_textctrl.SetValue('1.0')
        sff_post = wx.StaticText(panel, wx.ID_ANY,
                        'size of saved frame (in RF units, square)')

        sfs_pre = wx.StaticText(panel, wx.ID_ANY,
                                 'Save Frames Size: ')
        sfs_textctrl = wx.TextCtrl(panel, size=(150,-1))
        sfs_textctrl.SetValue('100')
        sfs_post = wx.StaticText(panel, wx.ID_ANY,
                        'size of saved frame (in pixels, square)')

        dsf_pre = wx.StaticText(panel, wx.ID_ANY,
                                 'Display Saved Frames: ')
        dsf_choice = wx.Choice(panel, choices=['Yes', 'No'])
        dsf_choice.SetStringSelection('No')
        dsf_post = wx.StaticText(panel, wx.ID_ANY,
                        'draw frames as they are rendered?')

        ok_button = wx.Button(panel, wx.ID_ANY, "Ok")
        self.Bind(wx.EVT_BUTTON, self.OnOk, ok_button)
        cancel_button = wx.Button(panel, wx.ID_ANY, 
                                  "Export without saving frames")
        self.Bind(wx.EVT_BUTTON, self.OnCancel, cancel_button)

        sizer0 = wx.BoxSizer(wx.HORIZONTAL)
        sizer1 = wx.BoxSizer(wx.HORIZONTAL)
        sizer2 = wx.BoxSizer(wx.HORIZONTAL)
        sizer3 = wx.BoxSizer(wx.HORIZONTAL)
        sizer4 = wx.BoxSizer(wx.HORIZONTAL)
        sizer  = wx.BoxSizer(wx.VERTICAL)

        CV = wx.ALIGN_CENTER_VERTICAL
        sizer0.Add(directions,   flag=CV)

        sizer1.Add(sff_pre,      flag=CV)
        sizer1.Add(sff_textctrl, flag=CV)
        sizer1.Add(sff_post,     flag=CV)

        sizer2.Add(sfs_pre,      flag=CV)
        sizer2.Add(sfs_textctrl, flag=CV)
        sizer2.Add(sfs_post,     flag=CV)

        sizer3.Add(dsf_pre,    flag=CV)
        sizer3.Add(dsf_choice, flag=CV)
        sizer3.Add(dsf_post,   flag=CV)

        sizer4.Add(cancel_button)
        sizer4.Add(ok_button)

        sizer.Add(sizer0, border=7, flag=wx.ALL|wx.ALIGN_CENTER)
        sizer.Add(sizer1, border=3, flag=wx.ALL|wx.ALIGN_CENTER)
        sizer.Add(sizer2, border=3, flag=wx.ALL|wx.ALIGN_CENTER)
        sizer.Add(sizer3, border=3, flag=wx.ALL|wx.ALIGN_CENTER)
        sizer.Add(sizer4, border=7, flag=wx.ALL|wx.ALIGN_CENTER)

        panel.SetSizer(sizer)

        main_sizer = wx.BoxSizer(wx.VERTICAL)
        main_sizer.Add(panel)
        self.SetSizerAndFit(main_sizer)

        self.sff = sff_textctrl
        self.sfs = sfs_textctrl
        self.dsf = dsf_choice

    def OnOk(self, event):
        self.kwargs = {'save_frames':True}
        self.kwargs['save_frames_factor'] = float(self.sff.GetValue())
        self.kwargs['save_frames_size'] = int(self.sfs.GetValue())
        self.kwargs['display_saved_frames'] = (self.dsf.GetStringSelection() 
                                               == 'Yes')
        print self.kwargs
        self.Close()

    def OnCancel(self, event):
        self.kwargs = {'save_frames':False}
        self.Close()



